using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web;
using Deepcode.Flux.Core.Services.FluxClient;

namespace Deepcode.Flux.Core.UI.Controls
{
	/// <summary>
	/// File reference control where the file can be already
	/// selected or a new one can be uploaded. File can be selected
	/// from within the asset manager.
	/// </summary>
	[ValidationProperty("Filename")]
	public class AssetFileUpload : Base.BaseControl, INamingContainer, IPostBackDataHandler	
	{
		#region Properties
		/// <summary>
		/// Determines what happens when a duplicate filename is uploaded
		/// if this is true, the file will simply be replaced. If it is
		/// false, the file being uploaded will be given a unique name.
		/// </summary>
		public bool OverwriteFiles
		{
			get
			{
				object o = ViewState["OverwriteFiles"];
				if( o == null ) return true;
				return (bool) o;
			}
			set
			{
				ViewState["OverwriteFiles"] = value;
			}
		}
		/// <summary>
		/// Determines if an asset can be selected 
		/// from the asset register (default is true)
		/// </summary>
		public bool CanSelect
		{
			get
			{
				object o = ViewState["CanSelect"];
				if( o == null ) return true;
				return (bool) o;
			}
			set
			{
				ViewState["CanSelect"] = value;
			}
		}
		/// <summary>
		/// Determines if the asset field can be empty or not. (note 
		/// this does not validate!) (default is true)
		/// </summary>
		public bool CanClear
		{
			get
			{
				object o = ViewState["CanClear"];
				if( o == null ) return true;
				return (bool) o;
			}
			set
			{
				ViewState["CanClear"] = value;
			}
		}
		/// <summary>
		/// Determines if the asset field should provide a 
		/// preview popup link (default is false).
		/// </summary>
		public bool CanPreview
		{
			get
			{
				object o = ViewState["CanPreview"];
				if( o == null ) return false;
				return (bool) o;
			}
			set
			{
				ViewState["CanPreview"] = value;
			}
		}
		/// <summary>
		/// Determines if the user can upload a new file
		/// directly from the control (default is true).
		/// </summary>
		public bool CanUpload
		{
			get
			{
				object o = ViewState["CanUpload"];
				if( o == null ) return true;
				return (bool) o;
			}
			set
			{
				ViewState["CanUpload"] = value;
			}
		}
		/// <summary>
		/// Determines the path used to upload files into 
		/// default is ~/assets
		/// </summary>
		public string UploadLocation
		{
			get
			{
				object o = ViewState["UploadLocation"];
				if( o == null ) return "~/assets";
				return (string) o;
			}
			set
			{
				ViewState["UploadLocation"] = value;
			}
		}
		/// <summary>
		/// Determines the path used as the asset browser
		/// root directory. Default is ~/assets
		/// </summary>
		public string SelectLocation
		{
			get
			{
				object o = ViewState["SelectLocation"];
				if( o == null ) return "~/assets";
				return (string) o;
			}
			set
			{
				ViewState["SelectLocation"] = value;
			}
		}
		/// <summary>
		/// Return the path and file of the selected item
		/// </summary>
		public string Filename
		{
			get
			{
				object o = ViewState["Filename"];
				if( o == null ) return "";
				return (string) o;

			}
			set
			{
				ViewState["Filename"] = value;
				if( this.SelectedText != null ) this.SelectedText.Text = value;
				if( this.SelectedFile != null ) this.SelectedFile.Value = value;
			}
		}
		#endregion
		#region Rendering override
		/// <summary>
		/// Render the control
		/// </summary>
		/// <param name="writer"></param>
		protected override void Render(HtmlTextWriter writer)
		{
			foreach( Control c in Controls )
				c.RenderControl( writer );
		}
		#endregion
		#region Initialisation
		/// <summary>
		/// Initialisation before rendering
		/// </summary>
		/// <param name="e"></param>
		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);
			
			Page.RegisterRequiresPostBack( this );
			
			// Ensure form has appropriate enctype for uploads
			HtmlForm form1 = this.Page.Form;
			if( (form1 != null) && (form1.Enctype.Length == 0))
				form1.Enctype = "multipart/form-data";

			// Register the script block
			this.LoadClientScript(
				"AssetFileUpload/afu.js", 
				"Deepcode.Flux.Core.UI.Controls.AssetFileUploadJS");

			// Load stylesheet
			this.LoadClientStyleSheet(
				"AssetFileUpload/afu.css",
				"Deepcode.Flux.Core.UI.Controls.AssetFileUploadCSS");

			// Generate the preview function
			BuildPreviewScript();
		}
		/// <summary>
		/// Outputs the script to open a preview window
		/// </summary>
		protected void BuildPreviewScript()
		{
			string s = "";
			s += "function AFU_Preview( fid )";
			s += "{";
			s += "	var ctrlValue = document.getElementById( fid + \"_value\" );";
			s += "	if( ctrlValue == null ) return false;";
			s += "	if( ctrlValue.value == \"\" ) return false;";
			s += String.Format("	var v = ctrlValue.value.replace(\"~/\", \"{0}\");", Page.ResolveUrl("~/"));
			s += "	var w = window.open(v, \"view\", \"width=400, height=400, resizable=yes\", true);";
			s += "	if (w.focus) w.focus();";
			s += "	return false;";
			s += "}";

			Page.ClientScript.RegisterClientScriptBlock( typeof( AssetFileUpload ),
				"AssetFileUploadPreview", s, true );
		}
		#endregion
		#region Persistent Controls
		protected TextBox		SelectedText = null;
		protected HiddenField	SelectedFile = null;
		protected FileUpload	FileUploader = null;
		#endregion
		#region Child control creation
		/// <summary>
		/// Creates the composite controls
		/// </summary>
		protected override void CreateChildControls()
		{
			// Main div
			HtmlGenericControl HostDiv = new HtmlGenericControl("DIV");
			HostDiv.Attributes.Add("id", this.ClientID);
			this.Controls.Add( HostDiv );

			// Selection area container
			HtmlGenericControl SelectionDiv = new HtmlGenericControl("DIV");
			SelectionDiv.ID = "select";
			HostDiv.Controls.Add( SelectionDiv );
			
			// Selection items table and row
			HtmlTable SelectIconsTable = new HtmlTable();
			SelectIconsTable.CellSpacing = 0;
			SelectIconsTable.CellPadding = 2;
			SelectIconsTable.Border = 0;
			SelectionDiv.Controls.Add( SelectIconsTable );
			HtmlTableRow SelectIconsRow = new HtmlTableRow();
			SelectIconsTable.Controls.Add( SelectIconsRow );
			
			// Cell with textbox
			HtmlTableCell CellSelectedText = new HtmlTableCell();
			SelectIconsRow.Controls.Add( CellSelectedText );
			SelectedText = new TextBox();
			SelectedText.ID = "text";
			SelectedText.CssClass = "AFU_Textbox";
			SelectedText.Text = this.Filename;
			SelectedText.Enabled = false;
			if( this.Width != Unit.Empty ) SelectedText.Width = this.Width;
			else SelectedText.Width = new Unit("150px");
			CellSelectedText.Controls.Add( SelectedText );

			// Cell with select icon
			if (this.CanSelect)
			{
				HtmlTableCell CellSelectNew = new HtmlTableCell();
				SelectIconsRow.Controls.Add(CellSelectNew);
				ImageButton Button = new ImageButton();
				Button.ImageUrl = ClientHelper.GetFluxClientFile("AssetFileUpload/img/select.gif");
				Button.OnClientClick = String.Format(
					"return AFU_Select('{0}', '{1}');",
					this.ClientID,
					Page.ResolveUrl("~/"));

				CellSelectNew.Controls.Add(Button);
			}
			// Cell with clear icon
			if (this.CanClear)
			{
				HtmlTableCell CellClear = new HtmlTableCell();
				SelectIconsRow.Controls.Add(CellClear);
				ImageButton Button = new ImageButton();
				Button.ImageUrl = ClientHelper.GetFluxClientFile("AssetFileUpload/img/remove.gif");
				Button.OnClientClick = String.Format(
					"return AFU_Clear('{0}');",
					this.ClientID);
				CellClear.Controls.Add(Button);
			}
			// Cell with preview icon
			if (this.CanPreview)
			{
				HtmlTableCell CellPreview = new HtmlTableCell();
				SelectIconsRow.Controls.Add(CellPreview);
				ImageButton Button = new ImageButton();
				Button.ImageUrl = ClientHelper.GetFluxClientFile("AssetFileUpload/img/preview.gif");
				Button.OnClientClick = String.Format(
					"return AFU_Preview('{0}');",
					this.ClientID);
				CellPreview.Controls.Add(Button);
			}
			// Cell with Upload mode icon
			if (this.CanUpload)
			{
				HtmlTableCell CellUpload = new HtmlTableCell();
				SelectIconsRow.Controls.Add(CellUpload);
				ImageButton Button = new ImageButton();
				Button.ImageUrl = ClientHelper.GetFluxClientFile("AssetFileUpload/img/mupload.gif");
				Button.OnClientClick = String.Format(
					"return AFU_UploadMode('{0}');",
					this.ClientID);
				CellUpload.Controls.Add(Button);
			}

			// Display the upload panel if available
			if( this.CanUpload )
			{
				// Upload area container
				HtmlGenericControl UploadDiv = new HtmlGenericControl("DIV");
				UploadDiv.ID = "upload";
				UploadDiv.Style.Add("display", "none");
				HostDiv.Controls.Add(UploadDiv);

				// Upload items table
				HtmlTable UploadIconsTable = new HtmlTable();
				UploadIconsTable.CellSpacing = 0;
				UploadIconsTable.CellPadding = 2;
				UploadIconsTable.Border = 0;
				UploadDiv.Controls.Add(UploadIconsTable);
				HtmlTableRow UploadIconsRow = new HtmlTableRow();
				UploadIconsTable.Controls.Add(UploadIconsRow);

				// Cell with the browse control
				HtmlTableCell CellUploadBrowse = new HtmlTableCell();
				UploadIconsRow.Controls.Add( CellUploadBrowse );
				FileUploader = new FileUpload();
				FileUploader.ID = "fileupload";
				FileUploader.CssClass = "AFU_Textbox";
				CellUploadBrowse.Controls.Add( FileUploader );

				// Cell with select mode control
				HtmlTableCell CellSelectMode = new HtmlTableCell();
				UploadIconsRow.Controls.Add(CellSelectMode);
				ImageButton Button = new ImageButton();
				Button.ImageUrl = ClientHelper.GetFluxClientFile("AssetFileUpload/img/mselect.gif");
				Button.OnClientClick = String.Format(
					"return AFU_SelectMode('{0}');",
					this.ClientID);
				CellSelectMode.Controls.Add(Button);
			}
			

			// Register the hidden fields
			// Selected file 
			SelectedFile = new HiddenField();
			SelectedFile.ID = "value";
			SelectedFile.Value = this.Filename;
			HostDiv.Controls.Add( SelectedFile );
			// Selection location
			HiddenField SelectionLocation = new HiddenField();
			SelectionLocation.ID="selectlocation";
			SelectionLocation.Value = this.SelectLocation;
			HostDiv.Controls.Add( SelectionLocation );
			// Field with current mode on it
			HiddenField CurrentMode = new HiddenField();
			CurrentMode.ID = "currentmode";
			CurrentMode.Value = "select";
			HostDiv.Controls.Add(CurrentMode);
		}
		#endregion
		#region IPostBackDataHandler Members
		/// <summary>
		/// Get the selected file if necessary and place it in
		/// the appropriate property.
		/// </summary>
		/// <param name="postDataKey"></param>
		/// <param name="postCollection"></param>
		/// <returns></returns>
		public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
		{
			// Process any value passed in on the value input first
			string s = postCollection[this.UniqueID + "$value"];
			if (this.Filename != s)
				this.Filename = s;
			
			// Check for a new file being specified
			HttpPostedFile f = this.Context.Request.Files[ this.UniqueID + "$fileupload" ];
			if( f != null && f.ContentLength>0 )
			{
				string cmode = postCollection[this.UniqueID + "$currentmode"];
				if (cmode == "upload")
				{
					// Ensure current mode reverts to select
					HiddenField hf = (HiddenField) this.FindControl("currentmode");
					if( hf != null ) hf.Value = "select";

					this.Filename = DoUpload( f );
				}
			}

			return false;
		}
		/// <summary>
		/// Not used
		/// </summary>
		public void RaisePostDataChangedEvent()
		{
		}
		#endregion
		#region Uploader
		/// <summary>
		/// Uploads the file and returns the web path to it
		/// </summary>
		/// <param name="ufile"></param>
		/// <returns></returns>
		protected string DoUpload(HttpPostedFile ufile)
		{
			// Ensure the upload location exists
			Deepcode.Flux.Core.Services.FileSystem.PathCheckService pcs = new Deepcode.Flux.Core.Services.FileSystem.PathCheckService();
			pcs.PathExists( this.UploadLocation, true );
			// Process the upload
			string sFilename = System.IO.Path.GetFileName( ufile.FileName );
			string WebUploadPath = this.UploadLocation;
			if (!WebUploadPath.EndsWith("/")) WebUploadPath += "/";
			string WebUploadFilename = WebUploadPath + sFilename;

			string MappedUploadPath = Page.Server.MapPath(WebUploadFilename);
			if (System.IO.File.Exists(MappedUploadPath))
			{
				if (this.OverwriteFiles)
				{
					ufile.SaveAs(MappedUploadPath);
					return WebUploadFilename;
				}
				else
				{
					// Need to obtain a unique name
					string sfile = System.IO.Path.GetFileNameWithoutExtension( ufile.FileName );
					string sext  = System.IO.Path.GetExtension( ufile.FileName );
					int iCounter = 1;

					while (true)
					{
						WebUploadFilename = String.Format("{0}{1}({2}){3}",
							WebUploadPath, sfile, iCounter, sext );

						MappedUploadPath = Page.Server.MapPath( WebUploadFilename );

						if( ! System.IO.File.Exists( MappedUploadPath ))
							break;
						iCounter++;
					}

					ufile.SaveAs( MappedUploadPath );
					return WebUploadFilename;
				}
			}
			else
			{
				ufile.SaveAs( MappedUploadPath );
				return WebUploadFilename;
			}
		}
		#endregion
	}
}
